import time
import numpy as np

from py2048 import board as board_class_0
from py2048_1 import Env as board_class_1
from py2048_2 import Env as board_class_2
from env_5bits_2048 import Env_2048 as board_class_3

def run_class_0(games_num):
    all_steps = 0
    a_time = time.time()
    for _ in range(games_num):
        state = board_class_0().popup().popup()
        score = 0
        step = 0
        while True:
            moves = [state.up(), state.right(), state.down(), state.left()]
            
            after, reward = max(moves, key = lambda move: move[1])
            if reward == -1:
                all_steps += step
                break
            state = after.popup()
            score += reward
            step += 1
    b_time = time.time()
    return b_time - a_time, all_steps


def run_class_1(games_num):
    env = board_class_1()
    all_step = 0

    a_time = time.time()
    for _ in range(games_num):    
        board, penalty = env.reset()
        step = 0
        while True:
            up_board = env.up(board)
            right_board = env.right(board)
            down_board = env.down(board)
            left_board = env.left(board)
            
            moves = [(up_board, env.get_score(up_board, penalty), "up"), 
                     (right_board, env.get_score(right_board, penalty), "right"), 
                     (down_board, env.get_score(down_board, penalty), "down"), 
                     (left_board, env.get_score(left_board, penalty), "left")]

            moves =[move for move in moves if move[0]!=board]
            
            if(not moves):
                all_step += step
                break

            after, _, _ = max(moves, key = lambda move: move[1])
            board, p = env.popup(after)
            penalty += p
            step += 1
    b_time = time.time()
    return b_time - a_time, all_step


def run_class_2(games_num):
    env = board_class_2()
    all_step = 0

    a_time = time.time()
    for _ in range(games_num):    
        board = env.reset()
        score = 0
        step = 0

        while True:
            moves = [env.up(board), env.right(board), env.down(board), env.left(board)]

            after, reward = max(moves, key = lambda move: move[1])
            if reward == -1:
                all_step += step
                break

            board = env.popup(after)
            score += reward
            step += 1
    b_time = time.time()
    return b_time - a_time, all_step


def run_class_3(games_num):
    all_step = 0
    env = board_class_3()

    a_time = time.time()
    for _ in range(games_num):    
        step = 0
        board, penalty = env.init_board()

        while True:
            ava_move, ava_board = env.available_move(board)
            if(not np.any(ava_move)):
                all_step += step
                break
            ava_board = np.array(ava_board)[ava_move]
            index = np.argmax([env.get_score(_board, 0) for _board in ava_board])
            board = ava_board[index]
                        
            step += 1
            board, p = env.insert_tile(board)
            penalty += p
    b_time = time.time()
    return b_time - a_time, all_step


if __name__ == '__main__':
    num = 10
    games_num = num*10000
    time_0, steps_0 = run_class_0(games_num)
    time_1, steps_1 = run_class_1(games_num)
    time_2, steps_2 = run_class_2(games_num)
    time_3, steps_3 = run_class_3(games_num)
    print("moporgic原始环境万次游戏的平均用时：  %.4f, 总步数：%d"%(time_0/num, steps_0))
    print("移动缓存表方法万次游戏的平均用时：     %.4f, 总步数：%d"%(time_1/num, steps_1))
    print("移动缓存表改进后方法万次游戏的平均用时：%.4f, 总步数：%d"%(time_2/num, steps_2))
    print("个人设计的缓存表方法万次游戏的平均用时：%.4f, 总步数：%d"%(time_3/num, steps_3))
